﻿using BJoin.Application.AppException;
using BJoin.Application.BObject;
using BJoin.Common;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Microsoft.FeatureManagement;
using System;
using System.Text;
using System.Threading.Tasks;

namespace BJoin.Application.WebApi.Controllers
{
    [ApiController]
    [Authorize]
    public class BaseController<T> : ControllerBase, IAsyncActionFilter where T : class
    {
        private readonly ILogger<T> _logger;
        private readonly IFeatureManager _featureManager;
        public BaseController(ILoggerFactory loggerFactory, IFeatureManagerSnapshot featureSnapshot)
        {
            _logger = loggerFactory?.CreateLogger<T>() ?? throw new ArgumentNullException(nameof(loggerFactory));
            _featureManager = featureSnapshot;
        }
        public IFeatureManager FeatureSnapshot=> _featureManager?? throw new ArgumentNullException(string.Format("{0} init fail", nameof(_featureManager)));
        public ILogger<T> Logger => _logger ?? throw new ArgumentNullException(string.Format("{0} init fail", nameof(_logger)));
        [NonAction]
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            _logger.LogInformation("the request process begin");
            if (!ModelState.IsValid)
                throw new HttpStatusCodeException(StatusCodes.Status400BadRequest, ToErrorString());
            if (context.HttpContext.Request.Headers.TryGetValue("username", out StringValues values))
            {
                context.HttpContext.Items.Add("actor", values[0]);
            }
            else
            {
                context.HttpContext.Items.Add("actor", "anonymous");
            }
            await next();
            _logger.LogInformation("the response process success end");
        }
        protected string ToErrorString(string split = "||")
        {
            StringBuilder errinfo = new StringBuilder();
            foreach (var s in ModelState.Values)
            {
                foreach (var p in s.Errors)
                {
                    errinfo.AppendFormat("{0}{1}", string.IsNullOrWhiteSpace(p.ErrorMessage)? p.Exception?.Message : p.ErrorMessage, split);
                }
            }
            if (errinfo.Length > split.Length)
            {
                errinfo.Remove(errinfo.Length - 2, split.Length);
            }
            return errinfo.ToString();
        }
        protected void CheckId(long[] id)
        {
            if(id.IsEmpty())
                throw new HttpStatusCodeException(StatusCodes.Status400BadRequest,
                    string.Format(EnumHelper.GetEnumDescription<EnumMessage>(EnumMessage.NotEmpty), nameof(id)));
            if (id.IsAny(i=>i<=0))
                throw new HttpStatusCodeException(StatusCodes.Status400BadRequest,
                    string.Format(EnumHelper.GetEnumDescription<EnumMessage>(EnumMessage.MustGreatZero), nameof(id)));
        }
        protected void CheckPagingParm(int pageIndex, int pageSize)
        {
            if (pageIndex < 0 || pageSize < 0)
                throw new HttpStatusCodeException(StatusCodes.Status400BadRequest,
                    string.Format(EnumHelper.GetEnumDescription<EnumMessage>(EnumMessage.MustGreatZero), nameof(pageIndex),nameof(pageSize)));
        }
    }
}
